package com.hulushuju.core.net.http;

import com.hulushuju.core.net.ContentType;
import com.hulushuju.core.net.cookie.CookieManager;
import com.hulushuju.core.net.exception.HttpException;
import com.hulushuju.core.net.http.callback.HttpCallback;
import com.hulushuju.core.net.http.okhttp.OkHttpClientImpl;
import lombok.Getter;
import okhttp3.OkHttpClient;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: Hanjiafeng
 * @Date: 2019-05-29
 * @Desc:
 */
public abstract class HttpClient {

    /**
     * 请求头头
     */
    @Getter
    protected final Map<String, List<String>> headers = new HashMap<>();
    /**
     * 请求对象
     */
    protected HttpRequest httpRequest;
    /**
     * 引擎
     */
    protected HttpEngine httpEngine;
    /**
     * Cookie管理器,用于http引擎写入和获取cookie
     */
    protected CookieManager cookieManager;
    /**
     * 此类中的时间单位
     */
    protected TimeUnit timeUnit = TimeUnit.SECONDS;
    /**
     * url
     */
    @Getter
    private String url;
    /**
     * 方法,默认GET
     */
    @Getter
    private HttpRequest.Method method = HttpRequest.Method.GET;
    /**
     * 表单数据格式
     */
    @Getter
    private ContentType contentType;
    /**
     * 表单数据,有表单数据时默认POST
     */
    @Getter
    private String formData;
    /**
     * 回调接口
     */
    @Getter
    private HttpCallback httpCallback;
    /**
     * 整个请求过程的超时时间,默认30秒
     */
    @Getter
    private long timeout = 30;
    /**
     * 连接超时时间,默认10秒
     */
    @Getter
    private long connectTimeout = 10;
    /**
     * 读取超时时间,默认20秒
     */
    @Getter
    private long readTimeout = 20;
    /**
     * 写入超时时间,默认20秒
     */
    @Getter
    private long writeTimeout = 20;
    /**
     * 默认连接池最大空闲连接数,默认5个
     */
    @Getter
    private int maxIdleConnections = 5;
    /**
     * 空闲连接存活时间,默认60秒
     */
    @Getter
    private long keepAliveDuration = 60;
    /**
     * 重定向,默认开启
     */
    @Getter
    private boolean followRedirects = true;
    /**
     * <code>HTTPS</code>到<code>HTTP</code>和<code>HTTP</code>到<code>HTTPS</code>的重定向,默认开启
     */
    @Getter
    private boolean followSslRedirects = true;

    /**
     * 返回实例
     *
     * @return 返回实例
     */
    public static HttpClient getInstance() {
        Class<OkHttpClientImpl> clientClass = OkHttpClientImpl.class;
        return new OkHttpClientImpl();
    }

    public HttpClient url(String url) {
        this.url = url;
        return this;
    }

    public HttpClient method(HttpRequest.Method method) {
        this.method = method;
        return this;
    }

    public HttpClient contentType(ContentType contentType) {
        this.contentType = contentType;
        return this;
    }

    public HttpClient formData(String formData) {
        this.formData = formData;
        return this;
    }

    public HttpClient httpCallback(HttpCallback httpCallback) {
        this.httpCallback = httpCallback;
        return this;
    }

    public HttpClient timeout(long timeout) {
        this.timeout = timeout;
        return this;
    }

    public HttpClient connectTimeout(long connectTimeout) {
        this.connectTimeout = connectTimeout;
        return this;
    }

    public HttpClient readTimeout(long readTimeout) {
        this.readTimeout = readTimeout;
        return this;
    }

    public HttpClient writeTimeout(long writeTimeout) {
        this.writeTimeout = writeTimeout;
        return this;
    }

    public HttpClient maxIdleConnections(int maxIdleConnections) {
        this.maxIdleConnections = maxIdleConnections;
        return this;
    }

    public HttpClient keepAliveDuration(long keepAliveDuration) {
        this.keepAliveDuration = keepAliveDuration;
        return this;
    }

    public HttpClient followRedirects(boolean followRedirects) {
        this.followRedirects = followRedirects;
        return this;
    }

    public HttpClient followSslRedirects(boolean followSslRedirects) {
        this.followSslRedirects = followSslRedirects;
        return this;
    }

    /**
     * 执行请求
     *
     * @return 返回请求结果
     * @throws HttpException 执行异常
     */
    public abstract HttpResponse execute() throws HttpException;
}
